#include "edge.hpp"
#include "cell.hpp"
#include "mesh.hpp"
#include "util.hpp"
#include "mesh_testFunctions.hpp"
#include <catch2/catch_test_macros.hpp>
#include <sstream>

using namespace hms;

// TEST_CASE( "Calculating length of a edge" )
// {
// 	hms::Mesh mesh { {Vector2s{0,0}, Vector2s{3,4} } };
// 	mesh.addFace( IdxVector{0,1} );
// 	REQUIRE( mesh.edge(0).length() == Approx(5.0) );
// }

TEST_CASE( "Getting the normal vector to a edge, checking orientation" ){
	Mesh mesh;
	auto req = [&](Index e, Vector2s&& n ){
		return approxEqual(mesh.edge(e).normal(), n);
	};

	SECTION( "Rectangular mesh" )
	{
		mesh = testMeshRectangles(true);

		REQUIRE( req( 0, {-1, 0}) );
		REQUIRE( req( 1, {-1, 0}) );
		REQUIRE( req( 2, { 1, 0}) );
		REQUIRE( req( 3, { 1, 0}) );
		REQUIRE( req( 4, { 1, 0}) );
		REQUIRE( req( 5, { 1, 0}) );
		REQUIRE( req( 6, { 0,-1}) );
		REQUIRE( req( 7, { 0,-1}) );
		REQUIRE( req( 8, { 0, 1}) );
		REQUIRE( req( 9, { 0, 1}) );
		REQUIRE( req(10, { 0, 1}) );
		REQUIRE( req(11, { 0, 1}) );
	}
	SECTION( "Triangular mesh" )
	{
		mesh = testMeshTriangles(true);
		// mesh.findDomainCellEdges();
		
		/* this test may fail if hms::epsilon is decreased significantly */
		if ( hms::epsilon <= 1e-6 )
		{
			REQUIRE( req(0, { 0,-1}) );
			REQUIRE( req(1, {-0.94868330, 0.31622777}) );
			REQUIRE( req(2, {-0.94868330,-0.31622777}) );
			REQUIRE( req(3, {-0.31622777,-0.94868330}) );
			REQUIRE( req(4, { 0.70710678,-0.70710678}) );
			REQUIRE( req(5, {-0.94868330,-0.31622777}) );
			REQUIRE( req(6, {-0.70710678, 0.70710678}) );
			REQUIRE( req(7, { 0,1}) );
			REQUIRE( req(8, { 0.94868330, 0.31622777}) );
		}
	}
}

TEST_CASE( "Getting internal cell from boundary edge" )
{
	auto mesh { testMeshRectangles(true) };
	
	REQUIRE( mesh.edge( 0).domainCell() == 0 );
	REQUIRE( mesh.edge( 1).domainCell() == 1 );
	REQUIRE( mesh.edge( 4).domainCell() == 2 );
	REQUIRE( mesh.edge( 5).domainCell() == 3 );
	REQUIRE( mesh.edge( 6).domainCell() == 0 );
	REQUIRE( mesh.edge( 7).domainCell() == 2 );
	REQUIRE( mesh.edge(10).domainCell() == 1 );
	REQUIRE( mesh.edge(11).domainCell() == 3 );
	REQUIRE_THROWS( mesh.edge( 2).domainCell() );
	REQUIRE_THROWS( mesh.edge( 3).domainCell() );
	REQUIRE_THROWS( mesh.edge( 8).domainCell() );
	REQUIRE_THROWS( mesh.edge( 9).domainCell() );
}

#ifdef IGNORE

TEST_CASE( "Getting ghost cell from boundary edge" )
{
	auto mesh { testMeshRectangles() };
	mesh.findDomainCellEdges();
	
	REQUIRE( mesh.edge( 0).ghostCell().index() ==  4 );
	REQUIRE( mesh.edge( 1).ghostCell().index() ==  5 );
	REQUIRE( mesh.edge( 4).ghostCell().index() ==  6 );
	REQUIRE( mesh.edge( 5).ghostCell().index() ==  7 );
	REQUIRE( mesh.edge( 6).ghostCell().index() ==  8 );
	REQUIRE( mesh.edge( 7).ghostCell().index() ==  9 );
	REQUIRE( mesh.edge(10).ghostCell().index() == 10 );
	REQUIRE( mesh.edge(11).ghostCell().index() == 11 );
	REQUIRE_THROWS( mesh.edge( 2).ghostCell() );
	REQUIRE_THROWS( mesh.edge( 3).ghostCell() );
	REQUIRE_THROWS( mesh.edge( 8).ghostCell() );
	REQUIRE_THROWS( mesh.edge( 9).ghostCell() );
}

TEST_CASE( "Calculating midpoint of edge" )
{
	auto mesh { testMeshRectangles() };
	
	REQUIRE( mesh.edge( 0).midpoint() == Vector2s{-1  ,-0.5} );
	REQUIRE( mesh.edge( 1).midpoint() == Vector2s{-1  , 0.5} );
	REQUIRE( mesh.edge( 2).midpoint() == Vector2s{ 0  ,-0.5} );
	REQUIRE( mesh.edge( 3).midpoint() == Vector2s{ 0  , 0.5} );
	REQUIRE( mesh.edge( 4).midpoint() == Vector2s{ 1  ,-0.5} );
	REQUIRE( mesh.edge( 5).midpoint() == Vector2s{ 1  , 0.5} );
	REQUIRE( mesh.edge( 6).midpoint() == Vector2s{-0.5,-1  } );
	REQUIRE( mesh.edge( 7).midpoint() == Vector2s{ 0.5,-1  } );
	REQUIRE( mesh.edge( 8).midpoint() == Vector2s{-0.5, 0  } );
	REQUIRE( mesh.edge( 9).midpoint() == Vector2s{ 0.5, 0  } );
	REQUIRE( mesh.edge(10).midpoint() == Vector2s{-0.5, 1  } );
	REQUIRE( mesh.edge(11).midpoint() == Vector2s{ 0.5, 1  } );
}

#endif